from flask import Flask, request, Response, jsonify
import os
import time
import logging
import os
import json
import hashlib
import sqlite3


server = Flask(__name__)


# 配置日志记录
logging.basicConfig(filename='server.log', level=logging.INFO,
                    format='%(asctime)s - %(message)s')

SERVER_FILE_PATH = "server_files"

# 服务器下行速度限制（字节/秒）
CHUNKS_SIZE = 0.5
DOWNLOAD_SPEED_LIMIT = int(2 * 1024 * 1024)  # 1 MB/s


# 计算文件的哈希值
def calculate_file_hash(filepath):
    hash_md5 = hashlib.md5()
    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()


# 生成 range.json 文件
def generate_range_file(filename, chunk_size=1024 * 1024):  # 默认分块大小为 1MB
    filepath = os.path.join(SERVER_FILE_PATH, filename)
    if not os.path.exists(filepath):
        return None

    file_size = os.path.getsize(filepath)
    ranges = []

    start = 0
    while start < file_size:
        end = min(start + chunk_size - 1, file_size - 1)
        ranges.append({'start': start, 'end': end})
        start = end + 1
    # 计算文件的哈希值
    file_hash = calculate_file_hash(filepath)
    # 构建 range.json 内容
    range_data = {
        "filename": filename,     # 文件名
        "supports_resume": True,  # 是否支持断点续传
        "file_size": file_size,   # 文件大小
        "chunk_count": len(ranges),  # 分块个数
        "chunks": ranges,         # 每个分块的字节范围
        "file_hash": file_hash    # 文件的哈希值
    }
    with open(os.path.join(SERVER_FILE_PATH, f"{filename}.json"), 'w') as f:
        json.dump(range_data, f, indent=4)
    print(f"Generated range file for {filename}")
    return range_data


def upload_sql_file(filename, json_file):
    conn = sqlite3.connect('files.db')
    cursor = conn.cursor()

    # 读取 JSON 文件内容
    with open(json_file, 'r') as f:
        json_content = json.load(f)

    # 将 JSON 内容转换为字符串
    json_content_str = json.dumps(json_content)

    # 插入数据到数据库
    cursor.execute('''
        INSERT INTO files (filename, json_content) VALUES (?, ?)
    ''', (filename, json_content_str))

    conn.commit()
    conn.close()



@server.route('/download/<filename>', methods=['GET'])
def filedown_handler(filename):
    # 记录日志
    logging.info(f"Link accessed: /download/{filename}")

    filepath = os.path.join(SERVER_FILE_PATH, filename)
    if not os.path.exists(filepath):
        return Response("File not found", 404)

    # 检查请求头，判断是否需要 range.json
    if request.headers.get('Range') is None:
        # 返回 range.json
        range_data = generate_range_file(filename, chunk_size=int(CHUNKS_SIZE*1024 * 1024))
        return jsonify(range_data)
    else:
        # 处理 Range 请求，返回文件数据
        file_size = os.path.getsize(filepath)
        range_header = request.headers.get('Range', None)
        range_match = range_header.split('=')[1].split('-')
        start = int(range_match[0]) if range_match[0] else 0
        end = int(range_match[1]) if range_match[1] else file_size - 1

        if start >= file_size or end >= file_size or start > end:
            return Response("Invalid Range", 416)

        # 计算需要传输的字节数
        total_bytes = end - start + 1
        bytes_sent = 0
        start_time = time.time()

        def generate():
            nonlocal bytes_sent
            with open(filepath, 'rb') as f:
                f.seek(start)
                while bytes_sent < total_bytes:
                    remaining_bytes = total_bytes - bytes_sent
                    chunk_size = min(DOWNLOAD_SPEED_LIMIT, remaining_bytes)
                    data = f.read(chunk_size)
                    if not data:
                        break
                    bytes_sent += len(data)
                    yield data
                    # 计算传输时间并引入延迟
                    elapsed_time = time.time() - start_time
                    expected_time = bytes_sent / DOWNLOAD_SPEED_LIMIT
                    if expected_time > elapsed_time:
                        time.sleep(expected_time - elapsed_time)

        response = Response(generate(), 206, mimetype='application/octet-stream')
        response.headers['Content-Range'] = f'bytes {start}-{end}/{file_size}'
        response.headers['Accept-Ranges'] = 'bytes'
        return response


@server.route('/upload/<filename>', methods=['POST'])
def fileup_handler(filename):
    pass



if __name__ == '__main__':
    server.run(host='0.0.0.0', port=5000, debug=True)
